package cn.biplam.common.file;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;

import org.apache.poi.common.usermodel.Hyperlink;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFFont;
import org.apache.poi.hssf.usermodel.HSSFHyperlink;
import org.apache.poi.hssf.usermodel.HSSFRichTextString;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.hssf.util.Region;

import cn.biplam.common.file.excel.ExcelCellStyle;
import cn.biplam.common.file.excel.ExcelFont;
import cn.biplam.common.file.excel.ExcelHyperLink;
import cn.biplam.common.tools.TOOLS;
import cn.biplam.common.wrapper.ErrorMessage;

/**
 * Excel格式文本文件读取
 * 
 * @author WangSong 2009-7-28上午10:29:06
 * @version 1.0
 */
public class ExcelFileWrite {

	/** Excel路径名称 */
	private String filePath;
	/** 文件输入流对象 */
	private FileInputStream file = null;
	/** 文件输出流对象 */
	private FileOutputStream fileOut = null;
	/** Excel对象，对使用 */
	private HSSFWorkbook workbook;

	/**
	 * 构造方法
	 * 
	 * @param filePath
	 *        文件的名称(含路径)
	 * @throws ErrorMessage
	 */
	public ExcelFileWrite(String filePath) throws ErrorMessage {
		this.filePath = filePath;
		prepare();
	}

	/**
	 * 初始化环境
	 * 
	 * @throws ErrorMessage
	 */
	private void prepare() throws ErrorMessage {
		try {

			File mFile = new File(filePath);
			/**判断文件是否存在，如果不存在则创建excel*/
			if (!mFile.exists()) {
				ExcelFileWrite.createNewExcel(filePath);
			}
			/**初始化输入流*/
			file = new FileInputStream(filePath);
			/**初始化Excel对象*/
			workbook = new HSSFWorkbook(file);
			/**初始化输出流*/
			fileOut = new FileOutputStream(filePath);
		} catch (FileNotFoundException e) {
			throw new ErrorMessage(e);
		} catch (IOException e) {
			throw new ErrorMessage(e);
		}
	}
	
	/**
	 * 取Excel对象
	 * @return
	 */
	public HSSFWorkbook getHSSFWorkbook(){
		return workbook;
	}

	/**
	 * 创建sheet
	 * @param sheetName  sheet名称
	 * @throws ErrorMessage
	 */
	public void createSheet(String sheetName) throws ErrorMessage {
		try {
			fileOut = new FileOutputStream(filePath);
			if(workbook!=null && workbook.getSheet(sheetName)==null){
				workbook.createSheet(sheetName);
			}
			workbook.write(fileOut);
		} catch (IOException e) {
			exceptionWrite();
			throw new ErrorMessage(e);
		}finally{
			close();
		}
	}
	
	/**
	 * 设置列宽
	 * @param sheetName sheet名称
	 * @param columnIndex 列索引 从0开始
	 * @param width 列宽
	 */
	public void setColumnWidth(String sheetName,int columnIndex,int width){
		if(workbook!=null){
			HSSFSheet sheet = workbook.getSheet(sheetName);
			if(sheet!=null){
				sheet.setColumnWidth(columnIndex,width*36);
			}
		}
	}
	
	/**
	 * 设置行高
	 * @param sheetName sheet名字
	 * @param rowIndex 行索引 从0开始
	 * @param height 行高
	 */
	public void setRowHeight(String sheetName,int rowIndex,int height){
		if(workbook!=null){
			HSSFSheet sheet = workbook.getSheet(sheetName);
			if(sheet!=null){
				HSSFRow row = sheet.getRow(rowIndex);
				if(row!=null){
					row.setHeight((short)(height*16));
				}
			}
		}
	}
	
	/**
	 * 写单元格内容
	 * @param sheetIndex sheet索引 从0开始
	 * @param rowIndex 行所有 从0开始
	 * @param cellIndex 列索引 从 0 开始
	 * @param cellValue 列值
	 * @param style 样式对象
	 * @param link 超链接对象
	 * @param richText 是否是有换行或同一单元格不同颜色情况
	 * @param fontSyle 单元格字体不同颜色的样式
	 * @throws ErrorMessage 
	 */
	public void writeCell(int sheetIndex,
						  int rowIndex,
						  int cellIndex,
						  String cellValue,
						  HSSFCellStyle style,
						  HSSFHyperlink link,
						  boolean richText,
			              ArrayList<Object[]> fontSyle) throws ErrorMessage{
		HSSFSheet sheet = workbook.getSheetAt(sheetIndex);
		_wirteCell(sheet, rowIndex, cellIndex, cellValue,style,link,richText,fontSyle);
	}
	
	/**
	 * 写单元格内容
	 * @param sheetName sheet的名字
	 * @param rowIndex 行所有 从0开始
	 * @param cellIndex 列索引 从 0 开始
	 * @param cellValue 列值
	 * @param style 样式对象
	 * @param link 超链接对象
	 * @param richText 是否是有换行或同一单元格不同颜色情况
	 * @param fontSyle 单元格字体不同颜色的样式
	 * @throws ErrorMessage 
	 */
	public void writeCell(String sheetName,
						  int rowIndex,
						  int cellIndex,
						  String cellValue,
						  HSSFCellStyle style,
						  HSSFHyperlink link,
						  boolean richText,
			              ArrayList<Object[]> fontSyle) throws ErrorMessage{
		HSSFSheet sheet = workbook.getSheet(sheetName);
		_wirteCell(sheet, rowIndex, cellIndex, cellValue,style,link,richText,fontSyle);
	}
	
	/**
	 * 写excel合并单元格内容
	 * @param sheetIndex sheet索引 从0开始
	 * @param rowIndexStart 行索引开始行 从0开始
	 * @param rowIndexEnd 行索引结束行 从0开始
	 * @param cellIndexStart 列索引开始列 从 0 开始
	 * @param cellIndexStart 列索引结束列 从 0 开始
	 * @param cellValue 列值
	 * @param style 样式对象
	 * @param link 超链接对象
	 * @param richText 是否是有换行或同一单元格不同颜色情况
	 * @param fontSyle 单元格字体不同颜色的样式
	 * @throws ErrorMessage 
	 */
	public void writeCellMerging(int sheetIndex,
			                     int rowIndexStart,
			                     int rowIndexEnd,
			                     int cellIndexStart,
			                     int cellIndexEnd,
			                     String cellValue,
			                     HSSFCellStyle style,
			                     HSSFHyperlink link,
								 boolean richText,
					             ArrayList<Object[]> fontSyle) throws ErrorMessage{
		HSSFSheet sheet = workbook.getSheetAt(sheetIndex);
		_wirteCellMerging(sheet, rowIndexStart, rowIndexEnd, cellIndexStart, cellIndexEnd, 
				                      cellValue,style,link,richText,fontSyle);
	}
	
	/**
	 * 写excel合并单元格内容
	 * @param sheetName sheet名字
	 * @param rowIndexStart 行索引开始行 从0开始
	 * @param rowIndexEnd 行索引结束行 从0开始
	 * @param cellIndexStart 列索引开始列 从 0 开始
	 * @param cellIndexStart 列索引结束列 从 0 开始
	 * @param cellValue 列值
	 * @param style 样式对象
	 * @param link 超链接对象
	 * @param richText 是否是有换行或同一单元格不同颜色情况
	 * @param fontSyle 单元格字体不同颜色的样式
	 * @throws ErrorMessage 
	 */
	public void writeCellMerging(String sheetName,
			                     int rowIndexStart,
			                     int rowIndexEnd,
			                     int cellIndexStart,
			                     int cellIndexEnd,
			                     String cellValue,
			                     HSSFCellStyle style,
			                     HSSFHyperlink link,
								 boolean richText,
					             ArrayList<Object[]> fontSyle) throws ErrorMessage{
		HSSFSheet sheet = workbook.getSheet(sheetName);
		_wirteCellMerging(sheet, rowIndexStart, rowIndexEnd, cellIndexStart,
				        cellIndexEnd, cellValue,style,link,richText,fontSyle);
	}
	
	/**
	 * 创建新的excel文件
	 * @throws ErrorMessage
	 */
	public static void createNewExcel(String path) throws ErrorMessage{
		HSSFWorkbook wb = new HSSFWorkbook();
	    try {
	    	FileOutputStream fileOut = new FileOutputStream(path);
			wb.write(fileOut);
			fileOut.close();
		} catch (IOException e) {
			throw new ErrorMessage(e);
		}
	}
	
	/**
	 * 写单元格
	 * @param sheet  sheet对象
	 * @param rowIndex 行所有 从0开始
	 * @param cellIndex 列索引 从 0 开始
	 * @param cellValue 列值
	 * @param style 样式对象
	 * @param link 超链接对象
	 * @param richText 是否是有换行或同一单元格不同颜色情况
	 * @param fontSyle 单元格字体不同颜色的样式
	 * @throws ErrorMessage 
	 */
	@SuppressWarnings("deprecation")
	private void _wirteCell(HSSFSheet sheet,
			                int rowIndex,
			                int cellIndex,
			                String cellValue,
			                HSSFCellStyle style,
			                HSSFHyperlink link,
			                boolean richText,
			                ArrayList<Object[]> fontSyle) throws ErrorMessage{
		try {
			fileOut = new FileOutputStream(filePath);
			if(sheet!=null){
				HSSFRow row = sheet.getRow((short)rowIndex);
				if(row==null){
					row = sheet.createRow((short)rowIndex);
				}
				HSSFCell cell = row.createCell((short)cellIndex);
			    setCellValue(cell, cellValue, richText, fontSyle);
			    if(style!=null){
			    	cell.setCellStyle(style);
			    }
			    if(link!=null){
			    	cell.setHyperlink(link);
			    }
			}			
			workbook.write(fileOut);
		} catch (IOException e) {
			exceptionWrite();
			throw new ErrorMessage(e);
		}finally{
			close();
		}
	}
	
	/**
	 * 写合并单元格 
	 * @param sheet  sheet对象
	 * @param rowIndexStart 行索引开始行 从0开始
	 * @param rowIndexEnd 行索引结束行 从0开始
	 * @param cellIndexStart 列索引开始列 从 0 开始
	 * @param cellIndexStart 列索引结束列 从 0 开始
	 * @param cellValue 列值
	 * @param style 样式对象
	 * @param link 超链接对象
	 * @param richText 是否是有换行或同一单元格不同颜色情况
	 * @param fontSyle 单元格字体不同颜色的样式
	 * @throws ErrorMessage 
	 */
	@SuppressWarnings("deprecation")
	private void _wirteCellMerging(HSSFSheet sheet,
								   int rowIndexStart,
            					   int rowIndexEnd,
            					   int cellIndexStart,
            					   int cellIndexEnd,
            					   String cellValue,
            					   HSSFCellStyle style,
            					   HSSFHyperlink link,
         						   boolean richText,
        			               ArrayList<Object[]> fontSyle) throws ErrorMessage{
		try {
			fileOut = new FileOutputStream(filePath);
			if(sheet!=null){
				HSSFRow row = sheet.getRow((short)rowIndexStart);
				if(row==null){
					row = sheet.createRow((short)rowIndexStart);
				}
				
				HSSFCell cell = row.createCell((short)cellIndexStart);
				if(style!=null){
					cell.setCellStyle(style);
			    	setMergedStyle(sheet, rowIndexStart, rowIndexEnd, cellIndexStart, cellIndexEnd, style);
			    	
			    }
				 setCellValue(cell, cellValue, richText, fontSyle);
			    Region region = new Region(rowIndexStart,
                        				   (short)cellIndexStart,
                        				   rowIndexEnd,
                        				   (short)cellIndexEnd);
			    sheet.addMergedRegion(region);
			
			    if(link!=null){
			    	cell.setHyperlink(link);
			    }
			}
			workbook.write(fileOut);
		} catch (IOException e) {
			exceptionWrite();
			throw new ErrorMessage(e);
		}finally{
			close();
		}
	}
	
	private void setCellValue(HSSFCell cell,
			                  String value,
			                  boolean richText,
							  ArrayList<Object[]> fontSyle){
		if(!richText){
			cell.setCellValue(value);
		}else{
			HSSFRichTextString ts= new HSSFRichTextString(value); 
			if(fontSyle!=null && value!=null){
				String flag = null;
				HSSFFont font = null;
				for(int i=0;i<fontSyle.size();i++){
					value = ts.getString();
					flag = (String)fontSyle.get(i)[0];
					font = (HSSFFont)fontSyle.get(i)[1];
					if(flag!=null && font!=null && value.indexOf(flag)!=-1){
			        	ArrayList<int []> ary = TOOLS.getSplitGroupIndex(value, flag);
			        	value = value.replaceAll(flag," ");
			        	ts = new HSSFRichTextString(value);
			    		for(int[] spIndex:ary){
			    			int start = spIndex[0];
			    			int end = spIndex[1];
			    			ts.applyFont(start,end,font);
			    		}
					} 
				}
			}
			cell.setCellType(HSSFCell.CELL_TYPE_STRING); 
			cell.setCellValue(ts);    
		}
	}
	
	/**
	 * 设置合并单元格样式
	 * @param sheet  sheet对象
	 * @param rowIndexStart 行索引开始行 从0开始
	 * @param rowIndexEnd 行索引结束行 从0开始
	 * @param cellIndexStart 列索引开始列 从 0 开始
	 * @param cellIndexStart 列索引结束列 从 0 开始
	 * @param style 样式
	 */
	@SuppressWarnings("deprecation")
	private void setMergedStyle(HSSFSheet sheet,
			   int rowIndexStart,
			   int rowIndexEnd,
			   int cellIndexStart,
			   int cellIndexEnd,
			   HSSFCellStyle style){
		HSSFRow row = null;
		for(int i=rowIndexStart;i<=rowIndexEnd;i++){
			for(int j=cellIndexStart;j<=cellIndexEnd;j++){
				if(i!= rowIndexStart || j!=cellIndexStart){
					row = sheet.getRow((short)i);
					if(row==null){
						row = sheet.createRow((short)i);
					}
					row.createCell((short)j).setCellStyle(style);
				}
			}
		}
		
	}
	
	/**
	 * 写异常时写文件
	 */
	private void exceptionWrite(){
		try {
			workbook.write(fileOut);
		} catch (IOException e1) {
			e1.printStackTrace();
		}
	}

	/**
	 * 关闭输入输出流
	 * 
	 * @throws ErrorMessage
	 */
	public void close() throws ErrorMessage {
		try {
			if (file != null) {
				file.close();
			}
			if (fileOut != null) {
				fileOut.close();
			}
		} catch (IOException e) {
			throw new ErrorMessage(e);
		}
	}

	public static void main(String[] arg) throws ErrorMessage {
		
		ExcelFileWrite file = new ExcelFileWrite(
				"D:\\项目\\biplam资料\\Excel导入格式\\表结构信息的导入\\测试.xls");
		/**创建目录*/
		file.createSheet("目录1");
		file.createSheet("目录2");
		/**样式*/
		ExcelCellStyle cS = new ExcelCellStyle(file.getHSSFWorkbook());
		cS.setAlign(HSSFCellStyle.ALIGN_CENTER);
		cS.setVertical(HSSFCellStyle.VERTICAL_CENTER);
		cS.setBorder(HSSFCellStyle.BORDER_THIN, HSSFCellStyle.BORDER_THIN, 
				HSSFCellStyle.BORDER_THIN, HSSFCellStyle.BORDER_THIN);
		cS.setFontSize(15);
		cS.setFontItalic(true);
		cS.setFontBoldweight(12);
		cS.setFontUnderline(HSSFFont.U_SINGLE);
		cS.setFontColor(HSSFColor.BLUE.index);
		cS.setWrapText(true);
//		cS.setBackgroundColor(HSSFColor.YELLOW.index);
//		cS.setForegroundColor(HSSFColor.RED.index);
		
		/**超链接*/
		HSSFHyperlink link = ExcelHyperLink.getHyperLink(Hyperlink.LINK_DOCUMENT, "目录2");
		
		HSSFCellStyle style = cS.get();
		file.writeCellMerging("目录1",1,2,3,4, "ddddd",style,link,false,null);
		
		ArrayList<Object[]> al = new ArrayList<Object[]>(); 
		Object[] fontStyle = new Object[2];
		
		ExcelFont font = new ExcelFont(file.getHSSFWorkbook());
		font.setFontColor(HSSFColor.BLUE.index);
		fontStyle[0]="&";
		fontStyle[1]=font.getHSSFFont();
		al.add(fontStyle);
		
		file.writeCell("目录1",1,1, "f&ab&\n\rffffffffffffff",null,null,true,al);
		file.writeCell("目录1",1,2, "ggg",style,null,false,null);
	}
}
